package com.lccviolet;

/**
 * @Author LiChaochao
 * @Date 2021/9/2 12:33
 * @Description SingletonDemo 单例模式volatile使用
 */
public class SingletonDemo {
    /*
     * 解决办法三：
     * 使用volatile
     * */
    private static volatile SingletonDemo instance = null;

    private SingletonDemo() {
        System.out.println(Thread.currentThread().getName() + " come in construction method");
    }

    /*
     * 解决办法一：
     * 可在方法上加synchronized实现，但是为了一个实例对象锁住整个代码，大材小用。因此不推荐
     * */
    public static SingletonDemo getInstance() {
        /*
         * 解决办法二：
         * DCL，即double check lock，双端检锁机制。只锁住出问题的代码处
         * */
        if (instance == null) {
            synchronized (SingletonDemo.class) {
                if (instance == null) {
                    /*
                     * 安全问题：
                     * new语句分位3步，可能发生重排，1、3、2
                     * 当执行到第3步，使instance != null，但却没有完成初始化
                     * 此时其他线程在进来时，判断为false，直接return，结果只能是空的了
                     * */
                    instance = new SingletonDemo();
                }
            }
        }
        return instance;
    }

    public static void main(String[] args) {
        // main线程（即单线程）下
        /*System.out.println(SingletonDemo.getSingletonDemo() == SingletonDemo.getSingletonDemo());
        System.out.println(SingletonDemo.getSingletonDemo() == SingletonDemo.getSingletonDemo());
        System.out.println(SingletonDemo.getSingletonDemo() == SingletonDemo.getSingletonDemo());*/

        // 多线程下：构造方法被打印了多次
        for (int i = 0; i < 200; i++) {
            new Thread(() -> {
                SingletonDemo.getInstance();
            }, String.valueOf(i)).start();
        }
    }
}
